package com.mega.ycy;

import com.mega.ycy.common.CommonProxy;
import com.mega.ycy.common.item.ItemAYiSlashBlade;
import com.mega.ycy.common.item.ItemLoader;
import com.mega.ycy.mixin.EntityAccessor;
import com.mega.ycy.network.KillMessage;
import com.mega.ycy.network.NetworkHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiDownloadTerrain;
import net.minecraft.client.gui.GuiGameOver;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.resources.I18n;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.item.ItemStack;
import net.minecraft.server.MinecraftServer;
import net.minecraft.stats.StatList;
import net.minecraft.util.DamageSource;
import net.minecraft.util.MovementInputFromOptions;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.client.GuiIngameForge;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.Mod.Instance;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.*;
import net.minecraftforge.fml.server.FMLServerHandler;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;

import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

@Mod(
        modid = "yiciyuan",
        name = "Yiciyuan",
        version = "0.1",
        dependencies = "required-after:flammpfeil.slashblade",
        acceptedMinecraftVersions = "[1.12.2]"
)
public class Yiciyuan_EVENT {
    @Instance("yiciyuan")
    public static Yiciyuan_EVENT instance;
    @SidedProxy(
            clientSide = "com.mega.ycy.client.ClientProxy",
            serverSide = "com.mega.ycy.common.CommonProxy"
    )
    public static CommonProxy proxy;
    public static Saver<GuiScreen> SCREEN;
    public static HashSet<World> LOADED_WORLDS = new HashSet<>();
    public static HashSet<Entity> LOADED_ENTITIES = new HashSet<>();
    public static HashSet<Entity> RENDERABLE_ENTITIES = new HashSet<>();
    public static HashMap<ItemStack, Boolean> SAFE_ITEMSTACKS = new HashMap<>();
    public static DamageSource source = new DamageSource("") {
        public boolean isDamageAbsolute() {
            return true;
        }

        public boolean isMagicDamage() {
            return true;
        }

        public ITextComponent getDeathMessage(EntityLivingBase entityLivingBaseIn) {
            List<ITextComponent> m = new ArrayList<>();
            m.add(new TextComponentString("\u7684\u6570\u636e\u88ab\u62b9\u9664"));
            m.add(new TextComponentString("\u6d88\u901d\u4e86"));
            m.add(new TextComponentString("\u8ff7\u5931\u5728\u5f02\u6b21\u5143"));
            int index = (new Random()).nextInt(m.size());
            ITextComponent deathMessage = m.get(index);
            return entityLivingBaseIn.getDisplayName().appendSibling(deathMessage);
        }
    };

    public Yiciyuan_EVENT() {
    }

    public static boolean isDeath(Object o) {
        if (Objects.isNull(o))
            return false;
        if (o instanceof Entity && (ItemAYiSlashBlade.ycy_death.contains(((Entity) o).entityUniqueID) || ItemAYiSlashBlade.ycy_death2.contains((Entity) o))) {
            Random random = new Random();
            ((Entity) o).rotationPitch = random.nextInt();
            ((Entity) o).rotationYaw = random.nextInt();
            Minecraft.getMinecraft().entityRenderer.cameraZoom = random.doubles(2).sum();
            return true;
        }
        return false;
    }

    public static boolean sameEntity(Entity entity, Entity entity2) {
        return entity.getUniqueID().equals(entity2.entityUniqueID);
    }

    @SuppressWarnings("ALL")
    public static boolean isYcySlashBlade(Object o) {
        if (Objects.isNull(o))
            return false;
            return o.getClass().getSimpleName().equals("ItemAYiSlashBlade");
    }

    public static boolean isSafe(Object o) {
        if (Objects.isNull(o))
            return false;
        return o instanceof EntityPlayer
                && ((((EntityPlayer) o).inventory != null && ((EntityPlayer) o).inventory.hasItemStack(new ItemStack(ItemLoader.yiSlashBlade)))
                    || ItemAYiSlashBlade.ycy.contains(((EntityPlayer) o).getUniqueID().toString()));
    }

    public static EntityPlayer getServerPlayer(EntityPlayerSP playerSP) {
        MinecraftServer server = CommonProxy.serverInstance;
        EntityPlayerMP playerMP = null;
        if (server != null) {
            for (EntityPlayerMP mp : server.getPlayerList().getPlayers())
                if (sameEntity(mp, playerSP))
                    playerMP = mp;
        } else if (Minecraft.getMinecraft().getIntegratedServer() != null) {
            for (EntityPlayerMP mp : Minecraft.getMinecraft().getIntegratedServer().getPlayerList().getPlayers())
                if (sameEntity(mp, playerSP))
                    playerMP = mp;
        } else if (playerSP.world != null) {
            MinecraftServer server1 = playerSP.world.getMinecraftServer();
            if (server1 != null)
                for (EntityPlayerMP mp : server1.getPlayerList().getPlayers())
                    if (sameEntity(mp, playerSP))
                        playerMP = mp;
        }
        return playerMP;
    }

    public static boolean isIllegal(Object o) {
        if (Objects.isNull(o))
            return false;
        else {
            if (o instanceof GuiScreen) {
                GuiScreen screen = (GuiScreen) o;
                if (screen instanceof GuiGameOver)
                    return true;
                if (screen.getClass().getSimpleName().startsWith("Dea")
                        || screen.getClass().getSimpleName().startsWith("GuiGameOver")
                        || screen.getClass().getSimpleName().startsWith("Si")
                        || screen.getClass().getSimpleName().startsWith("GuiDea"))
                    return true;
                List<GuiButton> buttons = screen.buttonList;
                AtomicBoolean is = new AtomicBoolean(false);
                buttons.forEach(button -> {
                    if (button.displayString.equals(I18n.format("deathScreen.respawn")) || button.displayString.startsWith("Res"))
                        is.set(true);
                });
                return is.get();
            }
        }
        return false;
    }

    public static void protectClientScreen() {
        if (isDeath(Minecraft.getMinecraft().player)) {
            CommonProxy.createFinalDeathScreen(Minecraft.getMinecraft());
            return;
        }
        if (!isSafe(Minecraft.getMinecraft().player) )
            return;
        if (Objects.isNull(SCREEN)) {
            if (Minecraft.getMinecraft().currentScreen instanceof GuiGameOver) {
                Minecraft.getMinecraft().currentScreen = null;
                Mouse.setCursorPosition(Display.getWidth() / 2, Display.getHeight() / 2);
                Mouse.setGrabbed(false);
            }
            else if (Minecraft.getMinecraft().currentScreen != null)
                SCREEN = new Saver<>(Minecraft.getMinecraft().currentScreen);
        }
        if (SCREEN != null && SCREEN.object() != null)
            if (Minecraft.getMinecraft().currentScreen instanceof GuiGameOver)
            {
                GuiScreen screen = SCREEN.object();
                if (!(screen instanceof GuiDownloadTerrain))
                    Minecraft.getMinecraft().currentScreen = SCREEN.object();
                else {
                    Minecraft.getMinecraft().currentScreen = null;
                    Mouse.setCursorPosition(Display.getWidth() / 2, Display.getHeight() / 2);
                    Mouse.setGrabbed(false);
                }
            }
        Minecraft mc = Minecraft.getMinecraft();
        if (CommonProxy.serverInstance != null)
            CommonProxy.serverInstance.setPlayerList(new SBPlayer.PL(CommonProxy.serverInstance, CommonProxy.serverInstance.playerList));
        if (mc.integratedServer != null)
            mc.integratedServer.setPlayerList(new SBPlayer.PL(mc.integratedServer, mc.integratedServer.playerList));
        if (mc.player == null || !mc.player.getClass().getName().equals(SBPlayer.SP.class.getName()))
            Yiciyuan_EVENT.replaceClientPlayer(mc);
    }

    public static void protectEntity(Object o) {
        if (Objects.isNull(o))
            return;
        if (o instanceof Entity) {
            Entity entity = (Entity) o;
            entity.isDead = false;
            entity.addedToChunk = true;
            entity.forceSpawn = true;
            entity.updateBlocked = false;
            if (!entity.isAddedToWorld())
                ((EntityAccessor) entity).setAddedToWorld(true);
            if (entity instanceof EntityLivingBase) {
                EntityLivingBase base = (EntityLivingBase) entity;
                base.deathTime = 0;
                base.hurtTime = 0;
                base.hurtResistantTime = 0;
            }
            if (entity instanceof EntityPlayer) {
                CommonProxy.save((EntityPlayer) o);
            }
        }
    }

    public static void killPlayer(EntityPlayer player) {
        if (!isSafe(player)) {
            ItemAYiSlashBlade.ycy_death.add(player.entityUniqueID);
            player.clearActivePotions();
            player.onDeath(source);
            player.setLastAttackedEntity(player);
            player.getCombatTracker().trackDamage(source, 3.4028235E38F, 3.4028235E38F);
            player.setHealth(0.0F);
            player.onKillEntity(player);
            player.world.setEntityState(player, (byte)2);
            player.addStat(StatList.DEATHS, 1);
            player.setLastAttackedEntity(player);
            NetworkHandler.INSTANCE.sendMessageToAll(new KillMessage(Minecraft.getMinecraft().world.playerEntities.indexOf(player)));
        }
    }

    private static void removeEntityDangerously(WorldServer world, Entity entityIn) {
        entityIn.setDropItemsWhenDead(false);
        entityIn.isDead = true;
        if (entityIn instanceof EntityPlayer)
        {
            world.playerEntities.remove(entityIn);
            world.updateAllPlayersSleepingFlag();
        }

        int i = entityIn.chunkCoordX;
        int j = entityIn.chunkCoordZ;

        if (entityIn.addedToChunk && world.isChunkLoaded(i, j, true))
        {
            world.getChunkFromChunkCoords(i, j).removeEntity(entityIn);
        }

        world.loadedEntityList.remove(entityIn);
        world.onEntityRemoved(entityIn);
    }

    public static void replaceClientPlayer(Minecraft mc) {
        mc.player = new SBPlayer.SP(mc.player);
        mc.player.preparePlayerToSpawn();
        if (mc.player.isDead)
            mc.player.isDead = false;
        if (!mc.player.isAddedToWorld())
            mc.player.onAddedToWorld();
        if (!mc.world.loadedEntityList.contains(mc.player))
            mc.world.loadedEntityList.add(mc.player);
        if (!mc.world.playerEntities.contains(mc.player))
            mc.world.playerEntities.add(mc.player);
        mc.world.entitySpawnQueue.add(mc.player);
        mc.world.entityList.add(mc.player);
        int i = MathHelper.floor(mc.player.posX / 16.0D);
        int j = MathHelper.floor(mc.player.posZ / 16.0D);

        if (mc.world.isChunkLoaded(i, j, false) && !mc.world.getChunkFromChunkCoords(i, j).entityLists[mc.player.chunkCoordY].contains(mc.player)) {
            mc.world.getChunkFromChunkCoords(i, j).entityLists[mc.player.chunkCoordY].add(mc.player);
            mc.world.getChunkFromChunkCoords(i, j).markDirty();
        }
        mc.player.movementInput = new MovementInputFromOptions(mc.gameSettings);
        mc.playerController.getCurrentGameType().configurePlayerCapabilities(mc.player.capabilities);
        mc.renderViewEntity = mc.player;
    }

    public static void killEntity(Entity entity) {
        try {
            if (Objects.isNull(entity))
                return;
            if (!isSafe(entity)) {
                if (entity.getClass().getSimpleName().equals("EntityChaosWither"))
                    Decide.removeChaosWither();
                ItemAYiSlashBlade.ycy_death2.add(entity);
                entity.capturedDrops = new ArrayList<>();
                ItemAYiSlashBlade.ycy_death.add(entity.entityUniqueID);
                entity.preventEntitySpawning = true;
                entity.forceSpawn = false;
                entity.updateBlocked = true;
                if (entity instanceof EntityLivingBase) {
                    EntityLivingBase livingBase = (EntityLivingBase)entity;
                    livingBase.isDead = true;
                }

                if (!entity.world.isRemote) {
                    Chunk chunk = entity.world.getChunkFromChunkCoords(entity.chunkCoordX, entity.chunkCoordZ);
                    World world = entity.world;
                    entity.world.loadedEntityList.remove(entity);
                    entity.isDead = true;
                    if (entity instanceof EntityPlayer)
                        world.playerEntities.remove(entity);
                    world.onEntityRemoved(entity);
                    world.onEntityRemoved(entity);
                    WorldServer worldServer = (WorldServer) entity.world;
                    removeEntityDangerously(worldServer, entity);
                    worldServer.onEntityRemoved(entity);
                    entity.onRemovedFromWorld();
                    chunk.setHasEntities(false);
                    chunk.markDirty();
                } else {
                    WorldClient worldClient = (WorldClient) entity.world;
                    entity.setDead();

                    if (entity instanceof EntityPlayer)
                    {
                        worldClient.playerEntities.remove(entity);
                        worldClient.updateAllPlayersSleepingFlag();
                        worldClient.onEntityRemoved(entity);
                    }
                    worldClient.entityList.remove(entity);
                    worldClient.onEntityRemoved(entity);
                    worldClient.removeEntityFromWorld(entity.getEntityId());
                }

                if (entity instanceof EntityPlayer) {
                    EntityPlayer player = (EntityPlayer)entity;
                    Iterator<?> var2;
                    EntityPlayerMP mp;
                    if (player.world.getMinecraftServer() != null) {
                        var2 = player.world.getMinecraftServer().playerList.getPlayers().iterator();

                        while(var2.hasNext()) {
                            mp = (EntityPlayerMP)var2.next();
                            if (sameEntity(mp, player)) {
                                killPlayer(mp);
                            }
                        }
                    } else if (Minecraft.getMinecraft().getIntegratedServer() != null) {
                        var2 = Minecraft.getMinecraft().getIntegratedServer().getPlayerList().getPlayers().iterator();

                        while(var2.hasNext()) {
                            mp = (EntityPlayerMP)var2.next();
                            if (sameEntity(mp, player)) {
                                killPlayer(mp);
                            }
                        }
                    }

                    killPlayer(player);
                }

            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }

    }

    @EventHandler
    public static void logging_(FMLServerAboutToStartEvent event) {
        CommonProxy.serverInstance = event.getServer();
    }

    @EventHandler
    public void logging2_(FMLServerAboutToStartEvent event) {
        CommonProxy.serverInstance = event.getServer();
        event.getServer().setPlayerList(new SBPlayer.PL(event.getServer(), event.getServer().playerList));

    }

    @EventHandler
    public void preInit_(FMLPreInitializationEvent event) {
        proxy.preInit(event);
    }

    @EventHandler
    public void init_(FMLInitializationEvent event) {
        proxy.init(event);
        Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(Yiciyuan_EVENT::protectClientScreen, 10, 10, TimeUnit.MICROSECONDS);
    }

    @EventHandler
    public void postInit_(FMLPostInitializationEvent event) {
        proxy.postInit(event);
    }

    @Mod.EventHandler
    public void onServerStarting_(FMLServerStartingEvent event) {
        event.registerServerCommand(new KillCommand());
        event.registerServerCommand(new ReganChunkCommand());
    }

    public static class ReganChunkCommand extends CommandBase {

        @Override
        public String getName() {
            return "Regan";
        }

        @Override
        public String getUsage(ICommandSender sender) {
            return "/Regan";
        }

        @Override
        public void execute(MinecraftServer server, ICommandSender sender, String[] args) {
        }
    }

    public static class KillCommand extends CommandBase {

        @Override
        public String getName() {
            return "YiciyuanKill";
        }

        @Override
        public String getUsage(ICommandSender sender) {
            return "/YiciyuanKill " + sender.getName();
        }

        @Override
        public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException {
            if (args.length == 0) {
                EntityPlayer entityplayer = getCommandSenderAsPlayer(sender);
                Minecraft mc = Minecraft.getMinecraft();
                replaceClientPlayer(mc);
                if (mc.getIntegratedServer() != null) {
                    mc.getIntegratedServer().setPlayerList(new SBPlayer.PL(mc.getIntegratedServer(), mc.getIntegratedServer().playerList));
                }
                if (FMLServerHandler.instance() != null && FMLServerHandler.instance().getServer() != null) {
                    FMLServerHandler.instance().getServer().setPlayerList(new SBPlayer.PL(FMLServerHandler.instance().getServer(), FMLServerHandler.instance().getServer().playerList));
                }
                Yiciyuan_EVENT.killEntity(entityplayer);
                Minecraft.getMinecraft().addScheduledTask(() -> {
                    Minecraft.getMinecraft().ingameGUI = new GuiIngameForge(Minecraft.getMinecraft());
                });
                notifyCommandListener(sender, this, "commands.kill.successful", entityplayer.getDisplayName());
            }
            else
            {
                Entity entity = getEntity(server, sender, args[0]);
                Yiciyuan_EVENT.killEntity(entity);
                notifyCommandListener(sender, this, "commands.kill.successful", entity.getDisplayName());
            }
        }
    }
}

